package com.gr.jron.dao.hibernate;

import com.gr.jron.dao.UserDao;
import com.gr.jron.model.User;
import org.acegisecurity.userdetails.UserDetails;
import org.acegisecurity.userdetails.UserDetailsService;
import org.acegisecurity.userdetails.UsernameNotFoundException;

import java.util.ArrayList;
import java.util.List;

/**
 * This class interacts with Spring's HibernateTemplate to save/delete and
 * retrieve User objects.
 *
 * @author <a href="mailto:matt@raibledesigns.com">Matt Raible</a>
 *         Modified by <a href="mailto:dan@getrolling.com">Dan Kibler</a>
 *         Extended to implement Acegi UserDetailsService interface by David Carter david@carter.net
 *         Modified by <a href="mailto:bwnoll@gmail.com">Bryan Noll</a> to work with
 *         the new BaseDaoHibernate implementation that uses generics.
 */
public class UserDaoHibernate extends GenericDaoHibernate<User, Long> implements UserDao, UserDetailsService {

    /**
     * Constructor that sets the entity to User.class.
     */
    public UserDaoHibernate() {
        super(User.class);
    }

    /**
     * {@inheritDoc}
     */
    @SuppressWarnings("unchecked")
    public List<User> getUsers(User user) {
        if (null == user) {
            return getHibernateTemplate().find("from User u order by upper(u.username)");
        } else {
            List jron = new ArrayList();
            if (!user.isEnabled()) jron.add("enabled");
            if (!user.isMobilePub()) jron.add("isMobilePub");
            if (!user.isNetTouchPub()) jron.add("isNetTouchPub");
            if (user.isAccountNonExpired()) jron.add("accountExpired");
            if (user.isCredentialsNonExpired()) jron.add("accountExpired");
            if (user.isAccountNonLocked()) jron.add("accountExpired");

            String[] exclude = new String[jron.size()];
            int i = 0;
            for (Object str : jron) {
                exclude[i++] = (String) str;
            }

            List results = findByExample(user, exclude);
            log.debug("The find users:" + results.size());
            return results;
        }

    }

    public User getUserByUsername(String username) {
        List users = getHibernateTemplate().find("from User where username=?", username);
        if (users == null || users.isEmpty())
            return null;
        return (User) users.get(0);
    }

    public User getUserByEmail(String email) {
        List users = getHibernateTemplate().find("from User where email=?", email);
        if (users == null || users.isEmpty())
            return null;
        return (User) users.get(0);
    }

    public Integer getUsersCount() {
        String hql = "from User u";
        return getCountByQuery(hql);
    }

    /**
     * {@inheritDoc}
     */
    public User saveUser(User user) {
        log.debug("user's id: " + user.getId());
        getHibernateTemplate().saveOrUpdate(user);
        // necessary to throw a DataIntegrityViolation and catch it in UserManager
        getHibernateTemplate().flush();
        return user;
    }

    /**
     * Overridden simply to call the saveUser method. This is happenening
     * because saveUser flushes the session and saveObject of BaseDaoHibernate
     * does not.
     *
     * @param user the user to save
     * @return the modified user (with a primary key set if they're new)
     */
    @Override
    public User save(User user) {
        return this.saveUser(user);
    }

    /**
     * {@inheritDoc}
     */
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        List users = getHibernateTemplate().find("from User where username=?", username);
        if (users == null || users.isEmpty()) {
            throw new UsernameNotFoundException("user '" + username + "' not found...");
        } else {
            return (UserDetails) users.get(0);
        }
    }

}
